package cn.kepu.elearning.service;

import cn.kepu.elearning.common.Constants;
import cn.kepu.elearning.common.JsonResult;
import cn.kepu.elearning.mapper.AllMapper;
import cn.kepu.elearning.util.ESUtil;
import cn.kepu.elearning.util.HtmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.*;

/**
 * @author Endy
 * @date 2020-04-21 上午8:37
 **/
@Service
@Slf4j
public class SyncService {

    public static final List<String> TRAIN_DATE_FIELDS = Arrays.asList("startTime", "endTime", "programStartTime", "programEndTime");
    public static final List<String> NEW_DATE_FIELDS = Arrays.asList("createTime");
    public static final List<String> NOTICE_DATE_FIELDS = Arrays.asList("validDate");

    @Autowired
    private AllMapper allMapper;
    @Value("${es.index}")
    private String index;

    @GetMapping("/sync")
    public JsonResult sync() {
        // 初始化之前先删除旧数据
        ESUtil.deleteIndex(index);
        log.info("索引【{}】删除成功", index);

        // 初始化索引
        ESUtil.initMappings(index);
        log.info("索引【{}】mapping初始化成功", index);

        // 同步数据
        syncNewsToEs();
        syncNoticeToEs();
        syncCourseToEs();
        syncTeacherToEs();
        syncTrainToEs();
        syncSeriesToEs();

        // 同步字典
        syncClassficationToEs();
        syncExpertAreaToEs();
        syncTrainTypeToEs();
        return new JsonResult();
    }

    private void syncCourseToEs() {
        int count = 0;
        int pageNum = 0;
        int offset = 0;
        int size = 1000;
        boolean hasNext = true;
        while (hasNext) {
            List<Map<String, Object>> list = allMapper.selectCourseByLimit(offset, size);
            if (CollectionUtils.isEmpty(list)) {
                break;
            }

            // 去除指定字段中的html标签
            for (Map<String, Object> map : list) {
                map.put("Content", map.get("Content") == null ? null : HtmlUtil.stripHtml(map.get("Content").toString()));
            }

            ESUtil.addOrUpdateDocuments(list, index, "course", "Course_id");
            if (size > list.size()) {
                hasNext = false;
            }
            offset = (++pageNum) * size;
            count += list.size();
        }
        log.info("课程同步完毕，数量：【{}】", count);
    }

    private void syncNewsToEs() {
        int count = 0;
        int pageNum = 0;
        int offset = 0;
        int size = 1000;
        boolean hasNext = true;
        while (hasNext) {
            List<Map<String, Object>> list = allMapper.selectNewsByLimit(offset, size);
            if (CollectionUtils.isEmpty(list)) {
                break;
            }

            for (Map<String, Object> map : list) {
                // 去除指定字段中的html标签
                map.put("newsContent", map.get("newsContent") == null ? null : HtmlUtil.stripHtml(map.get("newsContent").toString()));
                for (String field : NEW_DATE_FIELDS) {
                    if (map.get(field) != null) {
                        String programStartTime = Constants.ES_DATE_PATTERN.format((Date) map.get(field));
                        map.put(field, programStartTime);
                    }
                }
            }
            ESUtil.addOrUpdateDocuments(list, index, "news", "newsId");
            if (size > list.size()) {
                hasNext = false;
            }
            offset = (++pageNum) * size;
            count += list.size();
        }
        log.info("新闻同步完毕，数量：【{}】", count);
    }

    private void syncNoticeToEs() {
        int count = 0;
        int pageNum = 0;
        int offset = 0;
        int size = 1000;
        boolean hasNext = true;
        while (hasNext) {
            List<Map<String, Object>> list = allMapper.selectNoticeByLimit(offset, size);
            if (CollectionUtils.isEmpty(list)) {
                break;
            }

            for (Map<String, Object> map : list) {
                // 去除指定字段中的html标签
                map.put("content", map.get("content") == null ? null : HtmlUtil.stripHtml(map.get("content").toString()));
                for (String field : NOTICE_DATE_FIELDS) {
                    if (map.get(field) != null) {
                        String programStartTime = Constants.ES_DATE_PATTERN.format((Date) map.get(field));
                        map.put(field, programStartTime);
                    }
                }
            }
            ESUtil.addOrUpdateDocuments(list, index, "notice", "id");
            if (size > list.size()) {
                hasNext = false;
            }
            offset = (++pageNum) * size;
            count += list.size();
        }
        log.info("通知同步完毕，数量：【{}】", count);
    }

    private void syncTeacherToEs() {
        int count = 0;
        int pageNum = 0;
        int offset = 0;
        int size = 1000;
        boolean hasNext = true;
        while (hasNext) {
            List<Map<String, Object>> list = allMapper.selectTeacherByLimit(offset, size);
            if (CollectionUtils.isEmpty(list)) {
                break;
            }

            // 去除指定字段中的html标签
            for (Map<String, Object> map : list) {
                map.put("remark", map.get("remark") == null ? null : HtmlUtil.stripHtml(map.get("remark").toString()));
            }

            ESUtil.addOrUpdateDocuments(list, index, "teacher", "id");
            if (size > list.size()) {
                hasNext = false;
            }
            offset = (++pageNum) * size;
            count += list.size();
        }
        log.info("教师同步完毕，数量：【{}】", count);
    }

    private void syncTrainToEs() {
        int count = 0;
        int pageNum = 0;
        int offset = 0;
        int size = 1000;
        boolean hasNext = true;
        while (hasNext) {
            List<Map<String, Object>> list = allMapper.selectTrainByLimit(offset, size);
            if (CollectionUtils.isEmpty(list)) {
                break;
            }

            for (Map<String, Object> map : list) {
                for (String field : TRAIN_DATE_FIELDS) {
                    if (map.get(field) != null) {
                        String programStartTime = Constants.ES_DATE_PATTERN.format((Date) map.get(field));
                        map.put(field, programStartTime);
                    }
                }
                if (map.get("isEnrolled") != null) {
                    map.put("isEnrolled", (Boolean) map.get("isEnrolled") ? 1 : 0);
                }
            }
            ESUtil.addOrUpdateDocuments(list, index, "train", "id");
            if (size > list.size()) {
                hasNext = false;
            }
            offset = (++pageNum) * size;
            count += list.size();
        }
        log.info("培训同步完毕，数量：【{}】", count);
    }

    private void syncSeriesToEs() {
        int count = 0;
        int pageNum = 0;
        int offset = 0;
        int size = 1000;
        boolean hasNext = true;
        while (hasNext) {
            List<Map<String, Object>> list = allMapper.selectSeriesByLimit(offset, size);
            if (CollectionUtils.isEmpty(list)) {
                break;
            }
            for (Map<String, Object> map : list) {
                map.put("name",
                        Objects.isNull(map.get("name")) ?
                                new ArrayList<>() :
                                new ArrayList<>(
                                        Arrays.asList(map.get("name").toString().split("&\\|&"))
                                ));
            }

            ESUtil.addOrUpdateDocuments(list, index, "series", "id");
            if (size > list.size()) {
                hasNext = false;
            }
            offset = (++pageNum) * size;
            count += list.size();
        }
        log.info("系列专题同步完毕，数量：【{}】", count);
    }

    private void syncClassficationToEs() {
        List<Map<String, Object>> list = allMapper.selectClassfication();
        ESUtil.addOrUpdateDocuments(list, index, Constants.Type.CLASSFICATION, "id");
    }

    private void syncExpertAreaToEs() {
        List<Map<String, Object>> list = allMapper.selectExpertArea();
        ESUtil.addOrUpdateDocuments(list, index, Constants.Type.EXPERT_AREA, "CourseType_ID");
    }

    private void syncTrainTypeToEs() {
        List<Map<String, Object>> list = allMapper.selectTrainType();
        ESUtil.addOrUpdateDocuments(list, index, Constants.Type.TRAIN_TYPE, "id");
    }
}
